package com.yoso.starter.boot.util.file;

import cn.hutool.core.util.ReflectUtil;
import com.itextpdf.text.BaseColor;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Element;
import com.itextpdf.text.pdf.*;
import com.microsoft.schemas.office.office.CTLock;
import com.microsoft.schemas.vml.*;
import org.apache.poi.openxml4j.opc.PackagePartName;
import org.apache.poi.openxml4j.opc.PackageRelationship;
import org.apache.poi.openxml4j.opc.TargetMode;
import org.apache.poi.sl.usermodel.PictureData;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.wp.usermodel.HeaderFooterType;
import org.apache.poi.xslf.usermodel.XMLSlideShow;
import org.apache.poi.xslf.usermodel.XSLFPictureData;
import org.apache.poi.xslf.usermodel.XSLFPictureShape;
import org.apache.poi.xslf.usermodel.XSLFSlide;
import org.apache.poi.xssf.streaming.SXSSFSheet;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.apache.poi.xssf.usermodel.*;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFHeader;
import org.openxmlformats.schemas.officeDocument.x2006.sharedTypes.STTrueFalse;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.*;

import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.ArrayList;
import java.util.stream.Stream;


/**
 * 水印添加工具支持以下文件
 * Word添加文本水印，目前只支持.docx文件，透明度功能待定
 * Excel参考文章：https://juejin.cn/post/7208823936301973563
 * PDF
 * 图片输出为jpg
 */
public class WatermarkUtil {

    //一个字平均长度，单位pt，用于：计算文本占用的长度（文本总个数*单字长度）
    private static  int widthPerWord = 36;
    // 与顶部的间距
    private static float styleTop = 0;
    // 文本旋转角度
    private static final double styleRotation = -20;
    // 一行水印重复空格次数
    private static final int markSpace = 8;
    // 一行水印重复水印文字次数
    private static final int markNum = 5;
    //水印字体样式
    private static final String fontFamily = "宋体";
    /**
     * Excel 导出添加水印
     *
     * @param workbook ExcelWorkbook
     * @param waterMarkText  水印内容
     * @param fontColor 字体颜色
     * @param fontSize 字体大小
     * @param opacity 不透明度
     */
    public static void insertWaterMark(Workbook workbook, String waterMarkText,String fontColor, int fontSize, float opacity) throws IOException {
        doInsert(workbook, waterMarkText,fontColor,fontSize,opacity);
    }

    private static void doInsert(Workbook workbook, String waterMarkText,String fontColor, int fontSize, float opacity) throws IOException {
        if (workbook instanceof SXSSFWorkbook) {
            insertWaterMarkTextToXlsx((SXSSFWorkbook) workbook, waterMarkText,fontColor,fontSize,opacity);
        } else if (workbook instanceof XSSFWorkbook) {
            insertWaterMarkTextToXlsx((XSSFWorkbook) workbook, waterMarkText,fontColor,fontSize,opacity);
        }
    }

    /**
     * 给 Excel 添加水印
     *
     * @param workbook      SXSSFWorkbook
     * @param waterMarkText 水印文字内容
     * @param fontColor 字体颜色
     * @param fontSize 字体大小
     * @param opacity 不透明度
     */
    private static void insertWaterMarkTextToXlsx(SXSSFWorkbook workbook, String waterMarkText,String fontColor, int fontSize, float opacity) throws IOException {
        BufferedImage image = createWatermarkImage(waterMarkText,fontColor,fontSize,opacity);
        ByteArrayOutputStream imageOs = new ByteArrayOutputStream();
        ImageIO.write(image, "png", imageOs);
        int pictureIdx = workbook.addPicture(imageOs.toByteArray(), XSSFWorkbook.PICTURE_TYPE_PNG);
        XSSFPictureData pictureData = (XSSFPictureData) workbook.getAllPictures().get(pictureIdx);
        for (int i = 0; i < workbook.getNumberOfSheets(); i++) {
            SXSSFSheet sheet = workbook.getSheetAt(i);
            //这里由于 SXSSFSheet 没有 getCTWorksheet() 方法，通过反射取出 _sh 属性
            XSSFSheet shReflect = (XSSFSheet) ReflectUtil.getFieldValue(sheet, "_sh");
            PackagePartName ppn = pictureData.getPackagePart().getPartName();
            String relType = XSSFRelation.IMAGES.getRelation();
            PackageRelationship pr = shReflect.getPackagePart().addRelationship(ppn, TargetMode.INTERNAL, relType, null);
            shReflect.getCTWorksheet().addNewPicture().setId(pr.getId());
        }
    }

    /**
     * 给 Excel 添加水印
     *
     * @param workbook      XSSFWorkbook
     * @param waterMarkText 水印文字内容
     * @param fontColor 字体颜色
     * @param fontSize 字体大小
     * @param opacity 不透明度
     */
    private static void insertWaterMarkTextToXlsx(XSSFWorkbook workbook, String waterMarkText,String fontColor, int fontSize, float opacity) throws IOException {
        BufferedImage image = createWatermarkImage(waterMarkText,fontColor,fontSize,opacity);
        ByteArrayOutputStream imageOs = new ByteArrayOutputStream();
        ImageIO.write(image, "png", imageOs);
        int pictureIdx = workbook.addPicture(imageOs.toByteArray(), XSSFWorkbook.PICTURE_TYPE_PNG);
        XSSFPictureData pictureData = workbook.getAllPictures().get(pictureIdx);
        for (int i = 0; i < workbook.getNumberOfSheets(); i++) {
            XSSFSheet sheet = workbook.getSheetAt(i);
            PackagePartName ppn = pictureData.getPackagePart().getPartName();
            String relType = XSSFRelation.IMAGES.getRelation();
            PackageRelationship pr = sheet.getPackagePart().addRelationship(ppn, TargetMode.INTERNAL, relType, null);
            sheet.getCTWorksheet().addNewPicture().setId(pr.getId());
        }
    }

    /**
     * 创建水印图片
     * 图片自适应文字内容大小
     * @param waterMark 水印文字
     * @param fontColor 字体颜色
     * @param fontSize 字体大小
     * @param opacity 不透明度
     * 例子：ImageIO.write(createWaterMark("内部资料","00FF00",72,50), "png", outputfile);
     */
    private static BufferedImage createWatermarkImage(String waterMark, String fontColor, int fontSize, float opacity) {
        String[] textArray = waterMark.split("\n");
        Font font = new Font(fontFamily, Font.PLAIN, fontSize);
        BufferedImage image = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB);
        Graphics2D g2d = image.createGraphics();
        g2d.setFont(font);
        FontMetrics fontMetrics = g2d.getFontMetrics();
        int width = 0;
        int height = 0;
        // 计算水印图片的宽度和高度
        for (String s : textArray) {
            int textWidth = fontMetrics.stringWidth(s);
            if (textWidth > width) {
                width = textWidth;
            }
            height = height + fontMetrics.getHeight();
        }
        // 释放画笔
        g2d.dispose();
        // 计算倾斜后的高度
        double radians = Math.toRadians(styleRotation);
        int tiltedHeight = (int) Math.ceil(height / Math.cos(radians));
        // 计算实际高度
        height = tiltedHeight / 2 + (int) Math.round(Math.cos(20) * width);
        // 创建透明背景的水印图像
        image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
        g2d = image.createGraphics();
        // 背景透明
        g2d.setComposite(AlphaComposite.Clear);
        g2d.fillRect(0, 0, width, height);
        g2d.setComposite(AlphaComposite.Src);
        // 设定画笔颜色
        Color color = Color.decode("#" + fontColor); // 将RGB值字符串转换为Color对象
        int alpha = (int) Math.round(opacity / 100.0 * 255);
        color = new Color(color.getRed(), color.getGreen(), color.getBlue(), alpha);
        g2d.setColor(color);
        // 设置画笔字体
        g2d.setFont(font);
        // 设置字体平滑
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        //文字从中心开始输入，算出文字宽度，左移动一半的宽度，即居中
        // 水印位置
        int x = width / 2;
        int y = height / 2;
        // 设置水印旋转
        g2d.rotate(radians, x, y);
        for (String s : textArray) {
            // 文字宽度
            int textWidth = fontMetrics.stringWidth(s);
            // 画出字符串
            g2d.drawString(s, x - (textWidth / 2), y);
            y = y + fontMetrics.getHeight();
        }
        // 释放画笔
        g2d.dispose();
        return image;
    }




    /**
     * 给docx文档添加水印
     * 此方法可以单独使用
     * @param doc
     * @param customText
     */
    public static void waterMarkDocXDocument(XWPFDocument doc, String customText, String fontColor, int fontSize, float opacity){
        widthPerWord = fontSize;
        fontColor = ColorTransparency(fontColor,opacity);
        //水印行高
        float wordHight = 400f;
        // 水印文字之间使用8个空格分隔
        customText = repeatString(" ", markSpace) + customText;
        // 一行水印重复水印文字次数
        customText = repeatString(customText, markNum);
        //补充水印结尾空格
        customText = customText + repeatString(" ", markSpace);
        // 把整页都打上水印
        for (int lineIndex = -5; lineIndex < 20; lineIndex++) {
            styleTop = wordHight * lineIndex;
            // 添加默认页眉水印
            waterMarkDocXDocument_0(doc,customText,fontColor, HeaderFooterType.DEFAULT);
            // 添加第一页页眉水印
            waterMarkDocXDocument_0(doc,customText,fontColor,HeaderFooterType.FIRST);
        }
    }

    /**
     * 给docx文档添加水印
     * @param doc 需要被处理的docx文档对象
     * @param customText 需要添加的水印文字
     */
    public static void waterMarkDocXDocument_0(XWPFDocument doc,String customText, String fontColor,HeaderFooterType headerFooterType) {
        // 如果之前已经创建过 DEFAULT 的Header，将会复用
        XWPFHeader header = doc.createHeader(headerFooterType);
        int size = header.getParagraphs().size();
        if (size == 0) {
            header.createParagraph();
        }
        CTP ctp = header.getParagraphArray(0).getCTP();
        byte[] rsidr = doc.getDocument().getBody().getPArray(0).getRsidR();
        byte[] rsidrdefault = doc.getDocument().getBody().getPArray(0).getRsidRDefault();
        ctp.setRsidP(rsidr);
        ctp.setRsidRDefault(rsidrdefault);
        CTPPr ppr = ctp.addNewPPr();
        ppr.addNewPStyle().setVal("Header");
        // 开始加水印
        CTR ctr = ctp.addNewR();
        CTRPr ctrpr = ctr.addNewRPr();
        ctrpr.addNewNoProof();
        CTGroup group = CTGroup.Factory.newInstance();
        CTShapetype shapetype = group.addNewShapetype();
        CTTextPath shapeTypeTextPath = shapetype.addNewTextpath();
        shapeTypeTextPath.setOn(STTrueFalse.T);
        shapeTypeTextPath.setFitshape(STTrueFalse.T);
        CTLock lock = shapetype.addNewLock();
        lock.setExt(STExt.VIEW);
        CTShape shape = group.addNewShape();
        shape.setId("PowerPlusWaterMarkObject");
        shape.setSpid("_x0000_s102");
        shape.setType("#_x0000_t136");
        // 设置形状样式（旋转，位置，相对路径等参数）
        shape.setFillcolor(fontColor);
        shape.setStyle(getShapeStyle(customText));
        // 字体设置为实心
        shape.setStroked(STTrueFalse.FALSE);
        // 绘制文本的路径
        CTTextPath shapeTextPath = shape.addNewTextpath();
        // 设置文本类型
        shapeTextPath.setStyle("font-family:" + fontFamily);
        shapeTextPath.setString(customText);
        CTPicture pict = ctr.addNewPict();
        pict.set(group);
    }

    /**
     * 构建Shape的样式参数
     * @param customText
     * @return
     */
    private static String getShapeStyle(String customText) {
        StringBuilder sb = new StringBuilder();
        // 文本path绘制的定位方式
        sb.append("position: ").append("absolute");
        // 计算文本占用的长度（文本总个数*单字长度）
        sb.append(";width: ").append(customText.length() * widthPerWord).append("pt");
        // 字体高度
        sb.append(";height: ").append(2 * widthPerWord + "pt");
        sb.append(";z-index: ").append("-251654144");
        sb.append(";mso-wrap-edited: ").append("f");
        // 设置水印的间隔，这是一个大坑，不能用top,必须要margin-top。
        sb.append(";margin-top: ").append(styleTop);
        sb.append(";mso-position-horizontal-relative: ").append("page");
        sb.append(";mso-position-vertical-relative: ").append("page");
        sb.append(";mso-position-vertical: ").append("left");
        sb.append(";mso-position-horizontal: ").append("center");
        sb.append(";rotation: ").append(styleRotation);
        return sb.toString();
    }

    /**
     * 将指定的字符串重复repeats次.
     */
    private static String repeatString(String pattern, int repeats) {
        StringBuilder buffer = new StringBuilder(pattern.length() * repeats);
        Stream.generate(() -> pattern).limit(repeats).forEach(buffer::append);
        return new String(buffer);
    }

    /**
     * 根据透明度改变颜色，透明度为100时为白色，0时为初始颜色
     * @param fontColor 颜色
     * @param opacity 透明度（取值：0-100）
     * @return
     */
    public static String ColorTransparency(String fontColor,float opacity) {
        Color fontColorValue = Color.decode("#" +fontColor);
        int red = (int) ((255 - fontColorValue.getRed()) * (opacity / 100.0f));
        int green = (int) ((255 - fontColorValue.getGreen()) * (opacity / 100.0f));
        int blue = (int) ((255 - fontColorValue.getBlue()) * (opacity / 100.0f));
        Color newColor = new Color(255 - red, 255 - green, 255 - blue);
        String newColorStr = "#"+Integer.toHexString(newColor.getRGB()).substring(2);
        return newColorStr;
    }

    /**
     * 图片平铺水印
     * @param read 原图
     * @return
     * @throws IOException
     */
    public static void setWaterMarkToImg(Image srcImg,BufferedImage read, String waterMark, String fontColor, int fontSize, float opacity) throws IOException {



        // 1、源图片
        // Image srcImg = ImageIO.read(new File(srcImgPath));
        // BufferedImage buffImg = new BufferedImage(srcImg.getWidth(null),
        //        srcImg.getHeight(null), BufferedImage.TYPE_INT_RGB);

        // 2、得到画笔对象
        Graphics2D g = read.createGraphics();
        // 3、设置对线段的锯齿状边缘处理
        g.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
                RenderingHints.VALUE_INTERPOLATION_BILINEAR);
        g.drawImage(
                srcImg.getScaledInstance(srcImg.getWidth(null),
                        srcImg.getHeight(null), Image.SCALE_SMOOTH), 0, 0,
                null);
        // 4、设置水印旋转
        Integer degree=30;
        if (null != degree) {
            g.rotate(Math.toRadians(degree),
                    (double) read.getWidth() / 2,
                    (double) read.getHeight() / 2);
        }

        //Color color = Color.white;

        Font font = new Font("宋体", Font.BOLD, fontSize);

        Color color = Color.decode("#" + fontColor);

        // 5、设置水印文字颜色
        g.setColor(color);
        // 6、设置水印文字Font
        g.setFont(font);
        // 7、设置水印文字透明度
        g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, opacity  * 0.01f));

        //文字水印位置铺满全屏
        ArrayList position1;
        ArrayList position2;

        Integer allFlag=0;
        // 8、第一参数->设置的内容，后面两个参数->文字在图片上的坐标位置(x,y)
        if (allFlag == 1){
            int width = srcImg.getWidth(null);
            int height = srcImg.getHeight(null);
            position1 = new ArrayList();
            position2 = new ArrayList();
            position1.add(0);
            position1.add(width/4);
            position1.add(width/2);
            position1.add(width*3/4);
            position1.add(width);
            position2.add(0);
            position2.add(height/4);
            position2.add(height/2);
            position2.add(height*3/4);
            position2.add(height);

            for (int i = 0; i < position1.size(); i++) {
                for (int j = 0; j < position2.size(); j++) {
                    g.drawString(waterMark,(Integer) position1.get(i),(Integer) position2.get(j));
                }
            }
        }else {
            g.drawString(waterMark,0,0);
        }

        // 9、释放资源
        g.dispose();
        // 10、生成图片
        //os = new FileOutputStream(targerPath);
        //ImageIO.write(buffImg, "JPG", os);

        //将图片转为输出流
        // ByteArrayOutputStream baos = new ByteArrayOutputStream();
        // ImageIO.write(read, "jpg", baos);


    }

    /**
     * 图片居中水印
     * @param read 原图
     * @return
     * 例子：InputStream is = new FileInputStream(new File("C:\\Users\\yss\\Desktop\\timg.jpg"));
     *      OutputStream os = setWaterMarkToImg2(is, watermarkImg);
     * @throws IOException
     */
    public static OutputStream setWaterMarkToImg2(BufferedImage read,String waterMark, String fontColor, int fontSize, float opacity) throws IOException {
        //获取画布
        Graphics2D graphics = read.createGraphics();
        //获取水印图片
        BufferedImage bfi = createWatermarkImage(waterMark,fontColor,fontSize,opacity);
        //缩放水印图片
        int width = bfi.getWidth();
        int height = bfi.getHeight();
        //设置比例
        float f= 1f;
        //获取缩放后的宽度
        int w= (int) (width*f);
        int h= (int) (height*f);
        //缩放图片
        int x = (read.getWidth() - w) / 2;
        int y = (read.getHeight() - h) / 2;
        Image image = bfi.getScaledInstance(w, h, Image.SCALE_SMOOTH);
        //设置透明度，0->1，逐渐不透明
        graphics.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP,opacity  * 0.01f));
        //添加水印并设置在图片的右下角
        graphics.drawImage(image,x,y,null);
        //释放资源
        graphics.dispose();
        //将图片转为输出流
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ImageIO.write(read, "jpg", baos);
        //返回输出流
        return baos;
    }

    /**
     * PDF添加平铺水印
     * @param waterMark
     * @param fontColor
     * @param fontSize
     * @param opacity
     * @return
     * @throws IOException
     * @throws DocumentException
     * @throws DocumentException
     */
    public static ByteArrayOutputStream setWaterMarkToPdf(PdfReader reader,String waterMark, String fontColor, int fontSize, float opacity) throws IOException, DocumentException, DocumentException {
        //获取水印图片
        BufferedImage bfi = createWatermarkImage(waterMark,fontColor,fontSize,opacity);
        // 获取pdf页数
        int num = reader.getNumberOfPages();
        com.itextpdf.text.Rectangle pageSize;
        float width = 0f;
        float height = 0f;
        // 得到页面大小
        pageSize = reader.getPageSize(1);
        width = pageSize.getWidth();
        height = pageSize.getHeight();
        // 缩放水印图片
        int wWidth = bfi.getWidth();
        int wHeight = bfi.getHeight();
        // 每行水印图片数
        int wNum = 1
                ;
        // 计算水印图片的宽度
        float w = width / wNum;
        float h = w / wWidth * wHeight;
        // 缩放图片
        BufferedImage scaledImage = resizeImage(bfi, (int) w, (int) h);
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        ImageIO.write(scaledImage, "png", out);
        // 将图片放入pdf中
        com.itextpdf.text.Image image = com.itextpdf.text.Image.getInstance(out.toByteArray());
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        PdfStamper stamper = new PdfStamper(reader, bos);
        for (int i = 1; i <= num; i++) {
            // 水印图片设置在内容之上，之下用getUnderContent
            PdfContentByte pdfContentByte = stamper.getOverContent(i);
            // 计算水印图片布局
            int rows = (int) Math.ceil(height / h);
            int columns = wNum * num / rows;
            for (int row = 0; row < rows; row++) {
                for (int column = 0; column < columns; column++) {
                    int pageNum = row * columns + column + 1;
                    if (pageNum > num) {
                        break;
                    }
                    // 设置图片的位置
                    float x = column * w;
                    float y = height - ((row + 1) * h);
                    // 将水印图片添加到当前页
                    pdfContentByte.addImage(image, w, 0, 0, h, x, y);
                }
            }
        }
        stamper.close();
        reader.close();
        return bos;
    }

    /**
     * PDF添加平铺水印
     * @param waterMark
     * @param fontColor
     * @param fontSize
     * @param opacity
     * @return
     * @throws IOException
     * @throws DocumentException
     * @throws DocumentException
     */
    public static void setWaterMarkToPdf(PdfReader reader,String waterMark, String fontColor, int fontSize, float opacity,OutputStream outputStream) throws IOException, DocumentException, DocumentException {


        BufferedOutputStream bos = null;
        bos = new BufferedOutputStream(outputStream);

        com.itextpdf.text.pdf.PdfStamper stamper = new com.itextpdf.text.pdf.PdfStamper(reader, bos);

        // 获取总页数 +1, 下面从1开始遍历
        int total = reader.getNumberOfPages() + 1;
        // 使用classpath下面的字体库
        com.itextpdf.text.pdf.BaseFont base = null;

        try {
            base = com.itextpdf.text.pdf.BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", com.itextpdf.text.pdf.BaseFont.EMBEDDED);
        } catch (Exception e) {
            // 日志处理
            e.printStackTrace();
        }

        // 间隔
        int interval = -60;
        // 获取水印文字的高度和宽度
        int textH = 0, textW = 0;
        JLabel label = new JLabel();
        label.setText(waterMark);
        FontMetrics metrics = label.getFontMetrics(label.getFont());
        textH = metrics.getHeight();
        textW = metrics.stringWidth(label.getText());
//        System.out.println("textH: " + textH);
//        System.out.println("textW: " + textW);

        // 设置水印透明度
        com.itextpdf.text.pdf.PdfGState gs = new com.itextpdf.text.pdf.PdfGState();
        gs.setFillOpacity(opacity*0.01f);
        gs.setStrokeOpacity(opacity*0.01f);

        com.itextpdf.text.Rectangle pageSizeWithRotation = null;
        PdfContentByte content = null;
        for (int i = 1; i < total; i++) {
            // 在内容上方加水印
            content = stamper.getOverContent(i);
            content.saveState();
            content.setGState(gs);

            // 设置字体和字体大小
            content.beginText();
            content.setFontAndSize(base, fontSize);
            Color color1 = Color.decode("#" + fontColor);
            BaseColor color = new BaseColor(color1.getRGB());

            content.setColorFill(color);
            // 获取每一页的高度、宽度
            pageSizeWithRotation = reader.getPageSizeWithRotation(i);
            float pageHeight = pageSizeWithRotation.getHeight();
            float pageWidth = pageSizeWithRotation.getWidth();

            // 根据纸张大小多次添加， 水印文字成30度角倾斜
            for (int height = interval + textH; height < pageHeight; height = height + textH * 6) {
                for (int width = interval + textW; width < pageWidth + textW; width = width + textW * 2) {
                    content.showTextAligned(Element.ALIGN_LEFT, waterMark, width - textW, height - textH, 30);
                }
            }

            content.endText();
        }

        // 关流
        stamper.close();
        reader.close();

    }

    /**
     * PDF添加平铺水印    (区别上面的方法调整了字体大小 高度 宽度 固定透明度)
     * @author wengjingwen
     * @date 2023/10/7 13:48
     * @param reader
     * @param waterMark
     * @param fontColor
     * @param fontSize
     * @param opacity
     * @param outputStream
     * @return
     */
    public static void setWaterMarkToPdfFixed(PdfReader reader,String waterMark, String fontColor, int fontSize, float opacity,OutputStream outputStream) throws IOException, DocumentException {



        BufferedOutputStream bos = new BufferedOutputStream(outputStream);
        com.itextpdf.text.pdf.PdfStamper stamper = new com.itextpdf.text.pdf.PdfStamper(reader, bos);

        // 获取总页数 +1, 下面从1开始遍历
        int total = reader.getNumberOfPages() + 1;
        // 使用classpath下面的字体库
        BaseFont base = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", com.itextpdf.text.pdf.BaseFont.EMBEDDED);

        // 定义字体大小 文本高度 文本宽度 间隔
        int textH, textW, interval = -15;

        // 字体大小重新定义
        fontSize = Math.min(fontSize, 48);

        // 文本内容
        JLabel label = new JLabel();
        label.setText(waterMark);
        FontMetrics metrics = label.getFontMetrics(label.getFont());
        // 高度
        textH = metrics.getHeight() * 2;
        // 相乘倍数区别
        textW = fontSize <=36 ? (int) (metrics.stringWidth(label.getText()) * 1.5) : (metrics.stringWidth(label.getText()) * 2);

        // 设置水印透明度
        com.itextpdf.text.pdf.PdfGState gs = new com.itextpdf.text.pdf.PdfGState();
        gs.setFillOpacity(opacity * 0.01f);
        gs.setStrokeOpacity(opacity * 0.01f);

        com.itextpdf.text.Rectangle pageSizeWithRotation = null;
        PdfContentByte content = null;
        for (int i = 1; i < total; i++) {
            // 在内容上方加水印
            content = stamper.getOverContent(i);
            content.saveState();
            content.setGState(gs);

            // 设置字体和字体大小
            content.beginText();
            content.setFontAndSize(base, fontSize);
            Color color1 = Color.decode("#" + fontColor);
            BaseColor color = new BaseColor(color1.getRGB());

            content.setColorFill(color);
            // 获取每一页的高度、宽度
            pageSizeWithRotation = reader.getPageSizeWithRotation(i);
            float pageHeight = pageSizeWithRotation.getHeight();
            float pageWidth = pageSizeWithRotation.getWidth();


            // 计算斜30度后的水印坐标
            float radian = (float) Math.toRadians(30);
            float cos = (float) Math.cos(radian);
            float sin = (float) Math.sin(radian);

            for (int height = interval + textH; height < pageHeight; height = height + textH * 6) {
                for (int width = interval + textW; width < pageWidth + textW; width = width + textW * 2) {
                    float x = width * cos - height * sin;
                    float y = width * sin + height * cos;
                    content.showTextAligned(Element.ALIGN_LEFT, waterMark, x, y, 30);
                }
            }

            content.endText();
            content.restoreState();
        }

        // 关流
        stamper.close();
        reader.close();

    }


    /**
     * PDF添加平铺水印
     * @param waterMark
     * @param fontColor
     * @param fontSize
     * @param opacity
     * @return
     * @throws IOException
     * @throws DocumentException
     * @throws DocumentException
     */
    public static void setWaterMarkToPpt(XMLSlideShow reader, String waterMark, String fontColor, int fontSize, float opacity) throws IOException, DocumentException, DocumentException {
        //获取水印图片
        BufferedImage bfi = createWatermarkImage(waterMark,fontColor,fontSize,opacity);
        // 获取pdf页数
        int num = reader.getSlides().size();
        Dimension pageSize;
        double width = 0f;
        double height = 0f;
        // 得到页面大小
        pageSize = reader.getPageSize();
        width = pageSize.getWidth();
        height = pageSize.getHeight();
        // 缩放水印图片
        int wWidth = bfi.getWidth();
        int wHeight = bfi.getHeight();
        // 每行水印图片数
        int wNum = 1
                ;
        // 计算水印图片的宽度
        double w = width / wNum;
        double h = w / wWidth * wHeight;
        // 缩放图片
        BufferedImage scaledImage = resizeImage(bfi, (int) w, (int) h);
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        ImageIO.write(scaledImage, "png", out);
        // 将图片放入pdf中
        com.itextpdf.text.Image image = com.itextpdf.text.Image.getInstance(out.toByteArray());
        //ByteArrayOutputStream bos = new ByteArrayOutputStream();
        //PdfStamper stamper = new PdfStamper(reader, outputStream);
        XSLFPictureData pictureData=reader.addPicture(out.toByteArray(), PictureData.PictureType.PNG);
        for (int i = 1; i < num; i++) {
            // 水印图片设置在内容之上，之下用getUnderContent
            //PdfContentByte pdfContentByte = stamper.getOverContent(i);
            XSLFSlide slide=reader.getSlides().get(i);
            XSLFPictureShape pictureShape=slide.createPicture(pictureData);
            // 计算水印图片布局
            int rows = (int) Math.ceil(height / h);
            int columns = wNum * num / rows;
            for (int row = 0; row < rows; row++) {
                for (int column = 0; column < columns; column++) {
                    int pageNum = row * columns + column + 1;
                    if (pageNum > num) {
                        break;
                    }
                    // 设置图片的位置
                    double x = column * w;
                    double y = height - ((row + 1) * h);
                    // 将水印图片添加到当前页
                    //pdfContentByte.addImage(image, w, 0, 0, h, x, y);
                    pictureShape.setAnchor(new Rectangle((int)w,(int)h,(int)x,(int)y));

                }
            }
        }
        //stamper.close();
        //reader.close();
        //return bos;
    }


    private static BufferedImage resizeImage(BufferedImage bfi, int w, int h) {
        int type = bfi.getType() == 0 ? BufferedImage.TYPE_INT_ARGB : bfi.getType();
        BufferedImage scaledImage = new BufferedImage(w, h, type);
        Graphics2D g = scaledImage.createGraphics();
        g.drawImage(bfi, 0, 0, w, h, null);
        g.dispose();
        return scaledImage;
    }

}

